angular.module('custom.route', ['ui.router', 'oc.lazyLoad'])
    .provider('Route', ['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {

        var DEFAULT_SETTING = {
            filePrefix: 'src/view/',
            viewPrefix: 'src/view/',
            autoLoad  : {
                service   : true,
                controller: true
            }
        };

        var _parent   = '$$parent',
            _fullname = '$$fullname',
            _states   = {},
            _parseData;
        return {
            // provider access level
            config            : config,
            filePrefix        : filePrefix,
            viewPrefix        : viewPrefix,
            autoLoadService   : autoLoadService,
            autoLoadController: autoLoadController,
            setRoute          : setRoute,
            // controller access level
            $get              : function () {
                return {
                    getRoute: getRoute
                };
            }
        };

        function config(cfg) {
            angular.merge(DEFAULT_SETTING, cfg);
            return DEFAULT_SETTING;
        }

        function filePrefix(prefix) {
            prefix && (DEFAULT_SETTING.filePrefix = prefix);
            return DEFAULT_SETTING.filePrefix;
        }

        function viewPrefix(prefix) {
            prefix && (DEFAULT_SETTING.viewPrefix = prefix);
            return DEFAULT_SETTING.viewPrefix;
        }

        function autoLoadService(bool) {
            DEFAULT_SETTING.autoLoad.service = bool;
        }

        function autoLoadController(bool) {
            DEFAULT_SETTING.autoLoad.controller = bool;
        }

        function setRoute(route) {
            _parseData = _parse(route);
            _init();
        }

        function getRoute() {
            var states = angular.copy(_states), result = {};
            for (var key in states) {
                if (!states.hasOwnProperty(key)) {
                    continue;
                }
                if (key.indexOf('.') === -1) {
                    result[key] = states[key];
                } else {
                    var _key = key.replace(/\./g, '.children.');
                    angular.merge(result, _genObj(_key, states[key]));
                }
            }
            return result;
        }

        // private method
        // =====================================
        // 解析配置的 routeData
        function _parse(data, parents) {
            var result = {};
            parents = parents || [];
            angular.forEach(data, function (item) {
                // item 的上级 name
                item[_parent] = parents.join('.');
                parents.push(item.name);
                // 全称 用作 state.name. 上级的 parent + item.name
                var modelName = parents.join('.');
                item[_fullname] = modelName;
                result[modelName] = item;
                item.items && angular.extend(result, _parse(item.items, parents));
                // 保证同一级的下一次循环的 parents 一样, 在 parents.push(item.name) 后要再去删掉 push 的 name
                parents.pop();
            });
            return result;
        }

        // 通过解析后的数据 循环创建路由
        function _init() {
            // 遵循约定优于配置的原则自动批量注册路由
            angular.forEach(_parseData, function (state, name) {
                var paths     = name.split('.'), // base.core.msg => base/core/msg
                    lastState = name.match(/(\w+)$/)[0]; // base.core.msg => msg
                if (state.urlParams) {
                    lastState = state.name + '/' + state.urlParams;
                }
                angular.extend(state, {
                    url    : '/' + lastState,
                    resolve: _resolveFor(state)
                });
                if (DEFAULT_SETTING.autoLoad.controller && state.controller !== false) {
                    state.controller = state.controller || name;
                }
                if (state.templateUrl !== false) {
                    paths.push(paths[paths.length - 1]);
                    state.templateUrl = DEFAULT_SETTING.viewPrefix + paths.join('/') + '.html';
                }
                DEFAULT_SETTING.autoLoad.controller && (state.controllerAs = state.controllerAs || ctrlName(paths));
                // 循环创建 state
                $stateProvider.state(name, state);
                if (state.abstract && state.items && state.items.length) {
                    $urlRouterProvider.when(state.url, [function () {
                        var firstChild = state.items[0];
                        var names = firstChild.name.split('.');
                        return state.url + '/' + names.pop();
                    }]);
                }
            });
            angular.extend(_states, _parseData);
        }

        function ctrlName(paths) {
            if (paths.length === 0) {
                return '';
            }
            var prefix = '$';
            var name = prefix + paths.shift();
            paths.reverse().shift();
            angular.forEach(paths, function (item) {
                name += item.replace(/\w/, function (v) {
                    return v.toUpperCase();
                })
            });
            return name;
        }

        // Generates a resolve object by passing script names
        function _resolveFor(state) {
            return {
                deps: ['$ocLazyLoad', '$q', function ($ocLL, $q) {
                    // Creates a promise chain for each argument
                    var promise = $q.when(1); // empty promise
                    return promise.then(function () {
                        // if is a module, pass the name. If not,
                        // pass the array
                        var whatToLoad = _getRequired(state.name);
                        // 没找到匹配的文件
                        if (!whatToLoad) {
                            return;
                        }
                        // 返回 promise
                        return $ocLL.load(whatToLoad);
                    });
                }]
            };
        }

        // 查找配置中相应的js文件
        function _getRequired(name) {
            var state = _states[name], fileObj = state['files'] || [], files = [], hasHttpPrefix = /^http(s?):\/\//;
            if (DEFAULT_SETTING.autoLoad.controller && state.controller !== false) {
                if (!name) {
                    return console.error('请设置 route 的 name 属性');
                }
                var paths = name.split('.');
                //// 把controller文件放到name目录里面 而不是与 name 目录同级
                paths.push(paths[paths.length - 1]);
                var ctrlFile = paths.join('/') + '.ctrl.js';
                files.push(ctrlFile);
            }
            if (DEFAULT_SETTING.autoLoad.service && state.service !== false) {
                if (!name) {
                    return console.error('请设置 route 的 name 属性');
                }
                var paths = name.split('.');
                //// 把service文件放到name目录里面 而不是与 name 目录同级
                paths.push(paths[paths.length - 1]);
                var svcFile = paths.join('/') + '.svc.js';
                files.push(svcFile);
            }
            if (!angular.isArray(fileObj)) {
                fileObj = Object.keys(fileObj);
            }
            // files.push(fileObj[0],fileObj[1], fileObj[2], ..);
            Array.prototype.push.apply(files, fileObj);
            return files.map(function (item) {
                return hasHttpPrefix.test(item) ? item : (DEFAULT_SETTING.filePrefix + item); // 以 http:// 或 https:// 开头的不添加前缀
            });
        }

        function _genObj(key, value) {
            var result = {}, keys = key.split('.'), _key = keys.pop();
            result[_key] = value;
            if (keys.length) {
                return _genObj(keys.join('.'), result);
            }
            return result;
        }
    }]);
